// axios请求响应封装
import axios from "axios";
import { ElNotification } from "element-plus";
import router from "@/router/index";
import store from "@/store";
import md5 from "js-md5";

export const baseURL =
  process.env.NODE_ENV === "development" ? "/baseApi" : process.env.VUE_APP_URL;

// 创建 axios 实例
const request = axios.create({
  baseURL,
  // baseURL:'http://192.168.3.17:7000/api/',
  // baseURL:'http://60.204.144.143:10008/api/',
  timeout: 30000,
});

// token刷新动作执行与否。当多个接口同时报错token过期时，仅执行一次刷新。
let doRefreshTokenFlag = false;

// 刷新用户token
const updataTokenAPI = () => {
  // 一个刷新动作开始执行
  doRefreshTokenFlag = true;
  return request({
    method: "POST",
    url: "bf-user/auth/refreshToken",
    headers: {
      Authorization: `Bearer ${store.state.user.refreshToken}`,
    },
  });
};

/**
 * 生成key
 * @param config
 * @return {*}
 */
function getMd5String(config) {
  return md5(`${config.url}&${config.method}&${JSON.stringify(config.data)}&${JSON.stringify(config.params)}`);
}

let pending = {}; // 网络请求记录map结构
const CancelToken = axios.CancelToken;

// 请求拦截器
request.interceptors.request.use(
  function (config) {
    // 通过请求url、method、params、data字段生成md5值
 /*   const key = getMd5String(config);
    config.cancelToken = new CancelToken(c => {
      if (pending[key]) {
        // 上次接口未返回时走此逻辑
        if (Date.now() - pending[key] > 3000) {
          // 超过3s，删除对应的请求记录，重新发起请求,即使未返回
          delete pending[key];
        } else {
          // 同一请求未返回,3s内再次发送,取消发送
          c("repeated:" + config.url);
        }
      }
      // 记录当前的请求，已存在则更新时间戳
      pending[key] = Date.now();
    });*/

    /*
    config ：本次请求的配置对象，里面有一个属性：headers
    请求头未配置信息的时候才会配置
    */
    if (
      store.state.user.accessToken &&
      config.headers.Authorization === undefined
    ) {
      // 为每个请求携带自定义 token
      config.headers.Authorization = `Bearer ${store.state.user.accessToken}`;
    }
    // 这里必须将config返回出去，否则请求会停在这里
    return config;
  },
  function (error) {
    // 如果请求出错，在请求发出之前，就会进入这里
    return Promise.reject(error);
  }
);

// 响应拦截器
request.interceptors.response.use(
  function (response) {
   /* const key = getMd5String(response.config);
    if (pending[key]) {
      // 请求结束，删除对应的请求记录
      delete pending[key];
    }*/

    // 如果是文件流直接返回
    if (response.request) {
      if (
          response.request.responseType === 'blob' ||
          response.request.responseType === 'arraybuffer'
      ) {
        return response;
      }
    }





    // 获取请求的接口名，判断是否调用了登出接口
    let requestUrl = response.config.url.split("?")[0];
    let urlArr = requestUrl.split("/");
    let witchRequestName = urlArr[urlArr.length - 1];
    const { code, data, msg } = response.data;
    /*
    1.排除code='B2002'，'B2006'等，避免token过期后重复提示;
    2.排除登出接口报错时的提示
    */
    if (
      code &&
      code !== "200" &&
      code !== "B2002" &&
      code !== "B2006" &&
      witchRequestName !== "logout"
    ) {
      ElNotification.error({
        message: msg,
      });
    }
    return response.data;
  },
  async function (error) {
  /*  const key = getMd5String(error.config);
    if (pending[key]) {
      // 请求结束，删除对应的请求记录
      delete pending[key];
    }*/

    if (error.response && error.response.status === 401) {
      if (!doRefreshTokenFlag) {
        // 清除过期的accessToken
        store.commit("RESET_TOKEN");
        //请求刷新token接口
        const { data, code } = await updataTokenAPI();
        if (code === '200') {
          // 清除使用过的refreshToken
          store.commit("RESET_REFRESHTOKEN");
          //保存新的token值
          const newTokenObj = {
            access_token: data.access_token,
            refresh_token: data.refresh_token,
          };
          store.commit("SET_TOKEN", newTokenObj);

          /*
          再调用一次未完成的请求(用户无感知)
          error.config 就是上一次axios请求的配置对象
          把新的token赋予到下一次axios请求的请求头中
          */
          error.config.headers.Authorization = "Bearer " + data.access_token;

          // return到await的地方，将未完成的请求再次发起
          // return request(error.config);
          return axios(error.config);
        } else if (code === "B2002") {
          // refreshToken 失效
          ElNotification.error({
            message: "您的登录状态已失效,请重新登录!",
          });
          store.commit("RESET_STATE");
          setTimeout(() => {
            router.push("/login");
          }, 2000);
        } else {
          ElNotification.error({
            message: "您的登录状态已失效,请重新登录!",
          });
          store.commit("RESET_STATE");
          setTimeout(() => {
            router.push("/login");
          }, 2000);
        }
        // 2min后重置刷新动作，可重新执行token刷新
        setTimeout(() => {
          doRefreshTokenFlag = false;
        }, 1000 * 120);
      } else {
        // 刷新token动作已经执行过时
        if (store.state.user.accessToken) {
          error.config.headers.Authorization =
            "Bearer " + store.state.user.accessToken;
          return axios(error.config);
        }
      }
    } else {
      // error.response.status === 500 或其他情况
      ElNotification.error({
        message: "服务器异常，请联系管理员！",
      });
    }
    return Promise.reject(error);
  }
);

export default request;
